<template>
  <div class="p-2">
    <div style="color:#707070;font-size: 24px;font-weight: bold;margin-left: 10px;margin-bottom: 20px">CNN分类器设置</div>
    <el-form ref="cnnFormRef" :model="form" :rules="rules" label-width="80px">
      <el-form-item label="批次大小" prop="batchSize">
        <el-input v-model="form.batchSize" placeholder="请输入批次大小" />
      </el-form-item>
      <el-form-item label="迭代次数" prop="iterationNum">
        <el-input v-model="form.iterationNum" placeholder="请输入迭代次数" />
      </el-form-item>
      <el-form-item label="学习率" prop="learningRate">
        <el-input v-model="form.learningRate" placeholder="请输入学习率" />
      </el-form-item>
    </el-form>
    <div class="dialog-footer">
      <el-button :loading="buttonLoading" type="primary" @click="submitForm">开始分类</el-button>
      <el-button @click="reset">重 置</el-button>
    </div>
    <!-- 添加或修改【请填写功能名称】对话框 -->
    <el-dialog :title="dialog.title" v-model="dialog.visible" width="850px" append-to-body>
      <div style="color: #707070;font-size: 24px;text-align: center;margin-bottom: 10px">CNN模型训练结果</div>
      <div style="display: flex">
        <div class="chart" v-if="showTable">
          <line-charts width="400px" height="300px" :legend="legend" :series="series[0]" :x-axis="xAxis" />
          <div style="margin-left: 150px;margin-top: -30px">损失值：{{series[0].data[series[0].data.length - 1]}}</div>
        </div>
        <div class="chart" v-if="showTable">
          <line-charts width="400px" height="300px" :legend="legend" :series="series[1]" :x-axis="xAxis" />
          <div style="margin-left: 150px;margin-top: -30px">F1 score：{{series[1].data[series[1].data.length - 1]}}</div>
        </div>
      </div>
      <div class="button-group">
        <el-button type="warning" @click="cancel">重新训练</el-button>
        <el-button type="success" @click="saveData">保存模型及参数</el-button>
        <el-button type="primary" @click="exportData">保存结果</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script setup name="Cnn" lang="ts">
import { getCnn, addCnn, updateCnn } from '@/api/wyl/cnn';
import { CnnVO, CnnQuery, CnnForm } from '@/api/wyl/cnn/types';
import { propTypes } from "@/utils/propTypes";
import axios from "axios";
import { globalHeaders } from "@/utils/request";
import FileSaver from "file-saver";
import { blobValidate } from "@/utils/ruoyi";
import * as XLSX from "_xlsx@0.18.5@xlsx";
import { updateModelStatus } from "@/api/lsc/model";
import { updatePredStatus } from "@/api/wyl/prediction";

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({
  dataId: propTypes.string.def(""),
  predId: propTypes.string.def("")
});
const buttonLoading = ref(false);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const showTable = ref(false);


const queryFormRef = ref<ElFormInstance>();
const cnnFormRef = ref<ElFormInstance>();
const legend = ref([] as any[])
const series = ref([] as any[])
const xAxis = ref([] as any[])
const title = ref('CNN模型训练结果')

const dialog = reactive<DialogOption>({
  visible: false,
  title: ''
});

const initFormData: CnnForm = {
  id: undefined,
  predictionId: undefined,
  batchSize: undefined,
  iterationNum: undefined,
  learningRate: undefined,
}
const data = reactive<PageData<CnnForm, CnnQuery>>({
  form: {...initFormData},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    predictionId: undefined,
    batchSize: undefined,
    iterationNum: undefined,
    learningRate: undefined,
    params: {
    }
  },
  rules: {
    id: [
      { required: true, message: "不能为空", trigger: "blur" }
    ],
    predictionId: [
      { required: true, message: "不能为空", trigger: "blur" }
    ],
    batchSize: [
      { required: true, message: "批次大小不能为空", trigger: "blur" }
    ],
    iterationNum: [
      { required: true, message: "迭代次数不能为空", trigger: "blur" }
    ],
    learningRate: [
      { required: true, message: "学习率不能为空", trigger: "blur" }
    ],
  }
});

const { queryParams, form, rules } = toRefs(data);

/** 取消按钮 */
const cancel = () => {
  reset();
  dialog.visible = false;
}

/** 表单重置 */
const reset = () => {
  form.value = {...initFormData};
  cnnFormRef.value?.resetFields();
}

/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
}

/** 多选框选中数据 */
const handleSelectionChange = (selection: CnnVO[]) => {
  ids.value = selection.map(item => item.id);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}

/** 新增按钮操作 */
const handleAdd = () => {
  reset();
  dialog.visible = true;
  dialog.title = "添加【请填写功能名称】";
}

/** 修改按钮操作 */
const handleUpdate = async (row?: CnnVO) => {
  reset();
  const _id = row?.id || ids.value[0]
  const res = await getCnn(_id);
  Object.assign(form.value, res.data);
  dialog.visible = true;
  dialog.title = "修改【请填写功能名称】";
}

/** 提交按钮 */
const submitForm = async () => {
  cnnFormRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      await startTrain()
      dialog.visible = true
      await updatePredStatus(Object.assign({
        id: props.predId,
        state: '1',
      }))
    }
  });
}

const saveData = async () => {
  buttonLoading.value = true;
  form.value.predictionId = props.dataId;
  if (form.value.id) {
    await updateCnn(form.value).finally(() =>  buttonLoading.value = false);
  } else {
    await addCnn(form.value).finally(() =>  buttonLoading.value = false);
  }
  proxy?.$modal.msgSuccess("修改成功");
  dialog.visible = false;
}

/** 导出按钮操作 */
const handleExport = () => {
  proxy?.download('system/cnn/export', {
    ...queryParams.value
  }, `cnn_${new Date().getTime()}.xlsx`)
}
const baseURL = import.meta.env.VITE_APP_BASE_API;
const startTrain = async () => {
  await getData(String(props.dataId))
}
const stopTrain = () => {
  dialog.visible = false
}
const exportData = async () => {
  const url = baseURL + '/resource/oss/download/' + props.dataId;
  const res = await axios({
    method: 'get',
    url: url,
    responseType: 'blob',
    headers: globalHeaders()
  });
  const blob = new Blob([res.data], { type: 'application/octet-stream' });
  console.log('blob', blob)
  FileSaver.saveAs(blob, decodeURIComponent(res.headers['download-filename'] as string));
}

const getData = async (ossId: string) => {
  const url = baseURL + '/resource/oss/download/' + ossId;
  const res = await axios({
    method: 'get',
    url: url,
    responseType: 'blob',
    headers: globalHeaders()
  });
  const isBlob = blobValidate(res.data);
  if (isBlob) {
    const blob = new Blob([res.data], { type: 'application/octet-stream' });
    console.log('blob', blob)
    await readExcel(blob)
  }
}

const readExcel = async (file: Blob) => {
  // 确保有文件可读
  if (!file) {
    alert('请先选择一个Excel文件');
    return;
  }
  series.value = [];
  const reader = new FileReader();
  // 读取文件完成后的回调
  reader.onload = (event) => {
    const data = new Uint8Array((event.target as any).result);
    // 使用 xlsx 读取数据
    const workbook = XLSX.read(data, { type: 'array' });
    console.log("data", workbook)
    // 获取第一个工作表
    const firstSheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[firstSheetName];
    const jsonData = ref([] as any[])
    console.log("reader", jsonData.value)
    // 将 Excel 数据转换为 JSON 对象
    jsonData.value = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
    if (jsonData.value.length > 0) {
      jsonData.value[0].forEach((item: any) => {
        legend.value.push(item);
      });
    }
    xAxis.value = Array.from({ length: jsonData.value.length - 1 }, (_, i) => String(i + 1));
    for (let j = 0; j < jsonData.value[0].length; j++) {
      const colData = jsonData.value.slice(1).filter((row: string | any[]) => row.length >= 2).map((row: any[]) => row[j]);
      // 创建一个新的数据对象
      const newData = {
        name: legend.value[j],  // 使用 legend 中的数据作为 name 属性
        type: 'line',             // 设置 type 属性为 'line'
        smooth: true,
        data: colData             // 将列数据推导到 data 属性里
      };
      // 将数据对象添加到 dataDict 数组
      series.value.push(newData);
    }
    showTable.value = true;
    console.log("legend:", legend.value);
    console.log("series:", series.value);
  };
  // 读取文件为 ArrayBuffer
  reader.readAsArrayBuffer(file);
};
</script>

<style>
.dialog-footer{
  text-align: center;
}
.button-group{
  text-align: center;
  margin-top: 20px;
}
</style>
